/* 
 * File:   GpModel.h
 * Author: jcrada
 *
 * Created on April 4, 2009, 5:36 PM
 */

#ifndef _GPMODEL_H
#define	_GPMODEL_H

#include "TreeOfNodes.h"
#include "RandomNode.h"
#include "RandomGsl.h"
#include "GeneticOperators.h"
#include "TreeGenerator.h"

namespace jcrada {

    class GpModel {
    public:

        enum eGeneticOperator {
            GO_NONE = -1, GO_CROSSOVER, GO_REPRODUCTION, GO_MUTATION, GO_COUNT
        };

    private:
        int _population_size;
        TreeOfNodes ** _trees;

        TreeGenerator* _tree_generator;

        bool _lower_fitness_better;

        int _tournament_selection;
        RandomGsl _rnd_tournament;

        RandomGsl _rnd_genetic_operator;
        double g_operator[GO_COUNT];

        double _probability_crossover;
        double _probability_mutation;
        double _probability_reproduction;

        CrossoverOperator* _crossover_operator;
        MutationOperator* _mutation_operator;
        ReproductionOperator* _reproduction_operator;

    protected:

        virtual void setPopulationSize( int size ) {
            this->_population_size = size;
        }

        virtual void setTree( TreeOfNodes* tree, int position ) {
            assert(position >= 0 && position < getPopulationSize());
            this->_trees[position] = tree;
        }

        virtual eGeneticOperator nextGeneticOperator( );

    public:
        GpModel( int population_size );
        virtual ~GpModel( );

        virtual void create( );

        virtual TreeOfNodes& bestTournament( int k = 0 );
        virtual TreeOfNodes& worstTournament( int k = 0 );

        virtual TerminalNode* evaluate( const TreeOfNodes& tree, FunctionListener& listener );
        virtual TerminalNode* evaluate( const Node* node, FunctionListener& survivor );
        virtual void step( );

        static int main( int argc, char** argv );

        virtual TreeOfNodes& getTree( int position )const {
            assert(position >= 0 && position < getPopulationSize());
            return *_trees[position];
        }

        virtual int getPosition( const TreeOfNodes& tree ) {
            for (int i = 0; i < getPopulationSize(); ++i) {
                if (&getTree(i) == &tree) {
                    return i;
                }
            }
            return -1;
        }

        virtual int getPopulationSize( ) const {
            return this->_population_size;
        }

        virtual TreeGenerator& getTreeGenerator( ) const {
            return *this->_tree_generator;
        }

        virtual void setCrossoverOperator( CrossoverOperator* crossover_operator ) {
            this->_crossover_operator = crossover_operator;
        }

        virtual CrossoverOperator* getCrossoverOperator( ) const {
            return this->_crossover_operator;
        }

        virtual void setMutationOperator( MutationOperator* mutation_operator ) {
            this->_mutation_operator = mutation_operator;
        }

        virtual MutationOperator* getMutationOperator( ) const {
            return this->_mutation_operator;
        }

        virtual void setReproductionOperator( ReproductionOperator* reproduction_operator ) {
            this->_reproduction_operator = reproduction_operator;
        }

        virtual ReproductionOperator* getReproductionOperator( ) const {
            return this->_reproduction_operator;
        }

        virtual bool isBetter( double a, double b ) {
            return (isLowerFitnessBetter() ? a < b : a > b);
        }

        virtual void setProbabilityCrossover( double crossover ) {
            this->_probability_crossover = crossover;
        }

        virtual double getProbabilityCrossover( ) const {
            return this->_probability_crossover;
        }

        virtual void setProbabilityMutation( double mutation ) {
            this->_probability_mutation = mutation;
        }

        virtual double getProbabilityMutation( ) const {
            return _probability_mutation;
        }

        virtual void setProbabilityReproduction( double reproduction ) {
            this->_probability_reproduction = reproduction;
        }

        virtual double getProbabilityReproduction( ) const {
            return this->_probability_reproduction;
        }

        virtual void setTournamentSelection( int k_tournament ) {
            this->_tournament_selection = k_tournament;
        }

        virtual int getTournamentSelection( ) const {
            return this->_tournament_selection;
        }

        virtual void setLowerFitnessBetter( bool better ) {
            this->_lower_fitness_better = better;
        }

        virtual bool isLowerFitnessBetter( ) const {
            return this->_lower_fitness_better;
        }

    };
}

#endif	/* _GPMODEL_H */

